package configs

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"strings"
	"sync"
)

//>>>服务配置>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
type AppConf struct {
	Ip   string `json:"ip"`
	Port string `json:"port"`
}

type MysqlConf struct {
	Ip       string `json:"ip"`
	Port     string `json:"port"`
	Username string `json:"username"`
	Password string `json:"password"`
	DB       string `json:"db"`
}

type RedisConf struct {
	Ip       string `json:"ip"`
	Port     string `json:"port"`
	Password string `json:"password"`
	DB       string `json:"db"`
}

type NatsConf struct {
	Ip   string `json:"ip"`
	Port string `json:"port"`
}

type ESConf struct {
	Ip   string `json:"ip"`
	Port string `json:"port"`
}

type AliyunConf struct {
	AccessKeyId     string `json:"access_key_id"`
	AccessKeySecret string `json:"access_key_secret"`
	OssBucketName   string `json:"oss_bucket_name"`
	OssImgFolder    string `json:"oss_img_folder"`
	OssVideoFolder  string `json:"oss_video_folder"`
	OssFileFolder   string `json:"oss_file_folder"`
	OssEndpoint     string `json:"oss_endpoint"`
	OssBaseUrl      string `json:"oss_base_url"`
}

type AliPayConf struct {
	AppId            string `json:"app_id"`
	PrivateKey       string `json:"private_key"`
	AliPublicKey     string `json:"ali_public_key"`
	AliPayNotifyHost string `json:"ali_pay_notify_host"`
	AliPayReturnHost string `json:"ali_pay_return_host"`
	SuccessPage      string `json:"success_page"`
	ErrorPage        string `json:"error_page"`
	AliPayProd       string `json:"ali_pay_prod"`
}

type WXConf struct {
	AppId  string `json:"app_id"`
	Secret string `json:"secret"`
}

//>>>环境配置>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

type Conf struct {
	App     AppConf    `json:"app"`
	Mysql   MysqlConf  `json:"mysql"`
	Redis   RedisConf  `json:"redis"`
	Nats    NatsConf   `json:"nats"`
	ES      ESConf     `json:"es"`
	Aliyun  AliyunConf `json:"aliyun"`
	AliPay  AliPayConf `json:"ali_pay"`
	WX      WXConf     `json:"wx"`
	JwtKey  string     `json:"jwt_key"`
	Sha1Key string     `json:"sha1_key"`
	NatsUrl string     `json:"nats_url"`
	AmqpUrl string     `json:"amqp_url"`
	RpcUrl  string     `json:"rpc_url"`
}

//>>>总配置>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

type Configs struct {
	Dev Conf   `json:"dev"`
	Pro Conf   `json:"pro"`
	Env string `json:"env"`
}

var (
	conf            *Configs
	once            sync.Once
	lk              sync.Mutex
	defConfFilePath = "./app_config.json"
)

func json2struct(jsonstr string, st interface{}) (interface{}, error) {
	err := json.Unmarshal([]byte(jsonstr), st)
	if err != nil {
		return nil, err
	}
	return st, nil
}

func initConf() {
	lk.Lock()
	defer lk.Unlock()
	if conf == nil {
		once.Do(func() {
			file, err := os.Open(defConfFilePath)
			if err != nil {
				log.Fatal("读取配置文件失败")
			}
			defer file.Close()
			bt, err := ioutil.ReadAll(file)
			if err != nil {
				log.Fatal("读取配置文件失败")
			}
			conf_json := string(bt)
			conf = &Configs{}
			_, err = json2struct(conf_json, conf)
			if err != nil {
				fmt.Println(err)
				log.Fatal("读取配置文件失败")
			}
		})
	}
}

func init() {
	initConf()
}

func GetAppConf() AppConf {
	initConf()
	var c AppConf
	if conf != nil {
		switch GetENV() {
		case "dev":
			c = conf.Dev.App
		case "pro":
			c = conf.Pro.App
		default:
			c = conf.Dev.App
		}
	}
	return c
}

func GetMysqlConf() MysqlConf {
	initConf()
	var c MysqlConf
	if conf != nil {
		switch GetENV() {
		case "dev":
			c = conf.Dev.Mysql
		case "pro":
			c = conf.Pro.Mysql
		default:
			c = conf.Dev.Mysql
		}
	}
	return c
}

func GetRedisConf() RedisConf {
	initConf()
	var c RedisConf
	if conf != nil {
		switch GetENV() {
		case "dev":
			c = conf.Dev.Redis
		case "pro":
			c = conf.Pro.Redis
		default:
			c = conf.Dev.Redis
		}
	}
	return c
}

func GetESConf() ESConf {
	initConf()
	var c ESConf
	if conf != nil {
		switch GetENV() {
		case "dev":
			c = conf.Dev.ES
		case "pro":
			c = conf.Pro.ES
		default:
			c = conf.Dev.ES
		}
	}
	return c
}

func GetAliyunConf() AliyunConf {
	initConf()
	var c AliyunConf
	if conf != nil {
		switch GetENV() {
		case "dev":
			c = conf.Dev.Aliyun
		case "pro":
			c = conf.Pro.Aliyun
		default:
			c = conf.Dev.Aliyun
		}
	}
	return c
}

func GetAliPayConf() AliPayConf {
	initConf()
	var c AliPayConf
	if conf != nil {
		switch GetENV() {
		case "dev":
			c = conf.Dev.AliPay
		case "pro":
			c = conf.Pro.AliPay
		default:
			c = conf.Dev.AliPay
		}
	}
	return c
}

func GetWXConf() WXConf {
	initConf()
	var c WXConf
	if conf != nil {
		switch GetENV() {
		case "dev":
			c = conf.Dev.WX
		case "pro":
			c = conf.Pro.WX
		default:
			c = conf.Dev.WX
		}
	}
	return c
}

func GetJwtKeyConf() string {
	initConf()
	var c string
	if conf != nil {
		switch GetENV() {
		case "dev":
			c = conf.Dev.JwtKey
		case "pro":
			c = conf.Pro.JwtKey
		default:
			c = conf.Dev.JwtKey
		}
	}
	return c
}

func GetSha1KeyConf() string {
	initConf()
	var c string
	if conf != nil {
		switch GetENV() {
		case "dev":
			c = conf.Dev.Sha1Key
		case "pro":
			c = conf.Pro.Sha1Key
		default:
			c = conf.Dev.Sha1Key
		}
	}
	return c
}

func GetNatsUrlConf() string {
	initConf()
	var c string
	if conf != nil {
		switch GetENV() {
		case "dev":
			c = conf.Dev.NatsUrl
		case "pro":
			c = conf.Pro.NatsUrl
		default:
			c = conf.Dev.NatsUrl
		}
	}
	return c
}

func GetAmqpUrl() string {
	initConf()
	var c string
	if conf != nil {
		switch GetENV() {
		case "dev":
			c = conf.Dev.AmqpUrl
		case "pro":
			c = conf.Pro.AmqpUrl
		default:
			c = conf.Dev.AmqpUrl
		}
	}
	return c
}

func GetRpcUrl() string {
	initConf()
	var c string
	if conf != nil {
		switch GetENV() {
		case "dev":
			c = conf.Dev.RpcUrl
		case "pro":
			c = conf.Pro.RpcUrl
		default:
			c = conf.Dev.RpcUrl
		}
	}
	return c
}

func GetENV() string {
	return strings.ToLower(conf.Env)
}
